package top.zosoft;

import com.google.gson.Gson;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.mqtt.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * @Author：neal
 * @Package：top.zosoft
 * @Project：testmqtt
 * @name：SimpleHandler
 * @Date：2023/12/19 13:38
 * @Filename：SimpleHandler
 */
@Slf4j
public class SimpleHandler extends SimpleChannelInboundHandler<MqttMessage> {

    protected void channelRead0(ChannelHandlerContext ctx, MqttMessage msg) throws Exception {
        MqttMessageType messageType = msg.fixedHeader().messageType();
        switch (messageType) {
            case CONNECT:
                connAck(ctx, msg);
                break;
            case PUBLISH:
                pubReply(ctx, msg);
                break;
            case PUBREL:
                pubComp(ctx, msg);
                break;
            case SUBSCRIBE:
                subAck(ctx, msg);
                break;
            case UNSUBSCRIBE:
                unSubAck(ctx,msg);
                break;
            case PINGREQ:
                pingResp(ctx,msg);
                break;
            case DISCONNECT:
                dealDisconnect(ctx);
                break;
        }
    }

    public static void connAck(ChannelHandlerContext ctx, MqttMessage msg) {
        log.debug("收到连接请求");
        /**回复:CONNACK(2)
         * Fixed Header:00000010 00000000
         * Variable Header:packetID(messageID)
         */
        MqttConnectMessage connMessage = (MqttConnectMessage) msg;
        MqttFixedHeader fixedHeader = new MqttFixedHeader(MqttMessageType.CONNACK, false, MqttQoS.AT_MOST_ONCE, false, 2);
        MqttConnAckVariableHeader variableHeader = new MqttConnAckVariableHeader(MqttConnectReturnCode.CONNECTION_ACCEPTED, false);
        MqttConnAckMessage message = new MqttConnAckMessage(fixedHeader, variableHeader);
        ctx.writeAndFlush(message);
    }

    public static void pubReply(ChannelHandlerContext ctx, MqttMessage msg) {
        MqttQoS mqttQoS = ((MqttPublishMessage) msg).fixedHeader().qosLevel();
        int messageId = ((MqttPublishMessage) msg).variableHeader().packetId();
        MqttMessageIdVariableHeader variableHeader = MqttMessageIdVariableHeader.from(messageId);

        switch (mqttQoS) {
            case AT_MOST_ONCE:
                //qos=0
                break;
            case AT_LEAST_ONCE:
                /**回复:PUBACK(4)
                 * Fixed Header:01000000 00000010
                 * Variable Header:packetID(messageID)
                 */
                MqttFixedHeader fixedHeader1 = buildFiexHeader(MqttMessageType.PUBACK, false, MqttQoS.AT_MOST_ONCE, false, 2);
                MqttPubAckMessage message = new MqttPubAckMessage(fixedHeader1,variableHeader);
                ctx.writeAndFlush(message);
                break;
            case EXACTLY_ONCE:
                /**回复:PUBREC(5)
                 * Fixed Header:01010000 00000000
                 * Variable Header:packetID(messageID)
                 */
                MqttFixedHeader fixedHeader2 = buildFiexHeader(MqttMessageType.PUBREC, false, MqttQoS.AT_LEAST_ONCE, false, 2);
                MqttMessage message2 = new MqttMessage(fixedHeader2,variableHeader);
                ctx.writeAndFlush(message2);
                break;
            case FAILURE:
                break;
        }

    }

    public static void pubComp(ChannelHandlerContext ctx, MqttMessage msg) {
        log.debug("收到的消息：{}", new Gson().toJson(msg));
        /*  回复:PUBCOMP(7)
            Fixed Header:01110000 00000010
            Variable Header:packetID(messageID)
         */
        MqttFixedHeader fixedHeader = buildFiexHeader(MqttMessageType.PUBCOMP, false, MqttQoS.AT_MOST_ONCE, false, 2);
        MqttMessageIdVariableHeader variableHeader = MqttMessageIdVariableHeader.from(((MqttMessageIdVariableHeader) msg.variableHeader()).messageId());


        MqttMessage message = new MqttMessage(fixedHeader,variableHeader);
        ctx.writeAndFlush(message);
    }

    public static void subAck(ChannelHandlerContext ctx, MqttMessage msg) {
        log.debug("收到的消息：{}", new Gson().toJson(msg));
        /* 回复:SUBACK(9)
           Fixed Header:10010000  00000011
           Variable Header:packetID(messageID)
           Payload
         */
        MqttFixedHeader fixedHeader = buildFiexHeader(MqttMessageType.SUBACK, false, MqttQoS.AT_MOST_ONCE, false, 3);
        MqttMessageIdVariableHeader variableHeader = MqttMessageIdVariableHeader.from(((MqttMessageIdVariableHeader) msg.variableHeader()).messageId());
        MqttSubAckPayload payload = new MqttSubAckPayload(1);

        MqttSubAckMessage message = new MqttSubAckMessage(fixedHeader, variableHeader, payload);
        ctx.writeAndFlush(message);

    }

    public static void unSubAck(ChannelHandlerContext ctx,MqttMessage msg){
        log.debug("收到的消息：{}", new Gson().toJson(msg));
        /* 回复:UNSUBACK(11)
           Fixed Header:10110000  00000010
           Variable Header:packetID(messageID)
         */
        MqttFixedHeader fixedHeader = buildFiexHeader(MqttMessageType.UNSUBACK, false, MqttQoS.AT_MOST_ONCE, false, 2);
        MqttMessageIdVariableHeader variableHeader = MqttMessageIdVariableHeader.from(((MqttMessageIdVariableHeader) msg.variableHeader()).messageId());
        MqttUnsubAckMessage message = new MqttUnsubAckMessage(fixedHeader, variableHeader);
        ctx.writeAndFlush(message);

    }

    public static void pingResp(ChannelHandlerContext ctx,MqttMessage msg){
        log.debug("收到的消息：{}", new Gson().toJson(msg));
        /* 回复:PINGRESP(12)
           Fixed Header:11010000  00000000
         */
        MqttFixedHeader fixedHeader = buildFiexHeader(MqttMessageType.PINGRESP, false, MqttQoS.AT_MOST_ONCE, false, 0);
        MqttMessage message = new MqttMessage(fixedHeader);
        ctx.writeAndFlush(message);

    }
    public static void dealDisconnect(ChannelHandlerContext ctx){
        log.debug("收到关闭请求");
        ctx.channel().close();
    }

    public static MqttFixedHeader buildFiexHeader(MqttMessageType messageType, boolean isDup, MqttQoS qos, Boolean isRetain, int remainingLength) {
        return new MqttFixedHeader(messageType, isDup, qos, isRetain, remainingLength);
    }


}
